﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Threading;

using Perseus;
using Perseus.Plugins;

using Hetymine.Executioner.Commands;
using Hetymine.Executioner.Data;
using Hetymine.Executioner.Triggers;

namespace Hetymine.Executioner.Plugins.Triggers.DateTime {
    public class DateTime : TriggerPlugin {
        private DispatcherTimer _Timer;
        private List<DateTimeTrigger> _Triggers;

        public DateTime() {
            this.PluginInfo = PluginInfo.FromAssembly(
                "Date Time",
                this.GetType().Assembly,
                "Blake Hancock",
                "http://hetymine.com/executioner/plugins/trigger/datetime/"
            );

            Executioner.Loading += new EventHandler(Executioner_Loading);
            Executioner.Loaded += new EventHandler(Executioner_Loaded);
        }
        
        #region TriggerPluggin Members
        public override ITrigger InitializeTrigger() {
            return new DateTimeTrigger();
        }
        public override void TriggerLoaded(ITrigger trigger) {
            this._Triggers.Add(trigger as DateTimeTrigger);
        }
        #endregion

        private void Timer_Tick(object sender, EventArgs e) {            
            if (this._Triggers.Count == 0) {
                this._Timer.IsEnabled = false;
                return;
            }

            System.DateTime cDate = System.DateTime.Now;

            string today = cDate.ToString("yyyy-MM-dd");
            string now = cDate.ToString("yyyy-MM-dd HH:mm:ss");
            string last = Executioner.Config.GetString("Date Time", "Last Date", now);
            string date;
            
            List<DateTimeTrigger> triggers = new List<DateTimeTrigger>();

            // Add each matching trigger to list and then execute them
            foreach (DateTimeTrigger dtt in this._Triggers) {
                switch (dtt.DateType) {
                    case DateType.Daily:
                        date = today + " " + dtt.DateTime.ToString("HH:mm:ss");
                        if (date.CompareTo(last) == 1 && date.CompareTo(now) < 1) {
                            triggers.Add(dtt);
                        }
                        break;
                    case DateType.Weekly:
                        if (dtt.Days.ContainsToday(cDate.DayOfWeek)) {
                            date = today + " " + dtt.DateTime.ToString("HH:mm:ss");
                            if (date.CompareTo(last) == 1 && date.CompareTo(now) < 1) {
                                triggers.Add(dtt);
                            }
                        }
                        break;
                    case DateType.Once:
                        date = dtt.DateTime.ToString("yyyy-MM-dd HH:mm:ss");
                        if (date.CompareTo(last) == 1 && date.CompareTo(now) < 1) {
                            triggers.Add(dtt);
                        }
                        break;
                }
            }

            var commands = from tc in Executioner.Commands["Trigger"]
                           from dtt in ((TriggerCommand)tc).Triggers
                           where dtt is DateTimeTrigger &&
                           triggers.Contains((DateTimeTrigger)dtt)
                           select tc as TriggerCommand;

            foreach (TriggerCommand tc in commands) {
                tc.Execute(string.Empty, true);
            }

            Executioner.Config.SetString("Date Time", "Last Date", now);
        }

        private void Executioner_Loading(object sender, EventArgs e) {
            this._Triggers = new List<DateTimeTrigger>();
        }
        private void Executioner_Loaded(object sender, EventArgs e) {
            if (this._Triggers.Count == 0) {
                return;
            }

            string now = System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
            string last = Executioner.Config.GetString("Date Time", "Last Date", now);

            // If not first load, execute all missed one time executions
            if (!now.Is(last)) {
                var triggers = from d in this._Triggers
                               where d.DateType == DateType.Once &&
                               d.DateTime.ToString("yyyy-MM-dd HH:mm:ss").CompareTo(last) == 1
                               select d;

                var commands = from tc in Executioner.Commands["Trigger"]
                               from dtt in ((TriggerCommand)tc).Triggers
                               where dtt is DateTimeTrigger &&
                               triggers.Contains((DateTimeTrigger)dtt)
                               select tc as TriggerCommand;

                foreach (TriggerCommand tc in commands) {
                    tc.Execute(string.Empty);
                }
            }
            
            // Default to every 10 seconds
            int interval = Executioner.Config.GetInt("Date Time", "Interval", 10000);
            // Limit 10 ms to 1 hour
            interval = interval.MaxMin(10, 3600000);

            this._Timer = new DispatcherTimer();
            this._Timer.Interval = TimeSpan.FromMilliseconds(interval);            
            this._Timer.Tick += new EventHandler(Timer_Tick);
            this._Timer.IsEnabled = true;
        }
    }
}
